library ieee;
 use ieee.std_logic_1164.all;
 use ieee.std_logic_unsigned.all;


library work;
 use work.router_pack.all;

-------------------------------------------------------------------------------
entity msl_op is
-------------------------------------------------------------------------------
port( 
      -- General Control: --
      RESET     : in  std_logic;  -- Active Low 

      -- Internal Interface: --
      RH_ARR    : in  signaling_msl_bus_type;          -- pulse valid to OP .
      RBT_ARR   : in  signaling_msl_bus_type;          -- pulse valid to OP .
      DI        : in  data_msl_op_bus_type;            -- Busses from all IPs x SL x VC.
      AI_ARR    : out signaling_msl_bus_type;          -- Acknoweledge to all IPs (arr -- SLs).       

      -- External Interface: --
      RO        : out std_logic;
      AO        : in  std_logic;
      DO        : out std_logic_vector(vc_width+msl_ind_width+flit_width_con-1 downto 0)
);           
-------------------------------------------------------------------------------
end msl_op ;
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
architecture msl_op_arch of msl_op is
-------------------------------------------------------------------------------
component vcac
port( 
      -- General Control: --
      RESET      : in  std_logic;  -- Active Low 

      -- Interface to IPs: --
      H_ARR      : in  signaling_ssl_bus_type;  -- header requests from all the VCs x IPs 
      
      -- Interface to OPs: --
      RH_ARR_MTX : out signaling_ssl_bus_type;  -- Post MUTEX header requests from all the VCs x IPs 
      IPIDX_ARR  : out vcac_idx_out_type;
      VC_BUSY    : in  std_logic_vector(num_of_vc_con-1 downto 0);
      H_VCS      : in  std_logic_vector(num_of_vc_con-1 downto 0)  -- HREQ from SSL-OP (to reset SPA)           
);           
end component;

component msl_ssl_op_top 
port( 
      -- General Control: --
      RESET    : in  std_logic;  -- Active  

      -- Internal input i/f: --
      H_ARR    : in  signaling_ssl_bus_type;  -- #VCs (input) x #ports 
      BT_ARR   : in  signaling_ssl_bus_type;  -- #VCs (input) x #ports
      DATA_I   : in  data_ssl_op_bus_type;    -- #ports x #VCs (input)
      AI_ARR   : out signaling_ssl_bus_type;  -- #VCs (input) x #ports

      -- VCAC interface: --
      IPIDX    : in  vc_op_idx_type; --signaling_ssl_bus_type;  -- #VCs x #ports
      H        : out std_logic;
      BUSY     : out std_logic;

      -- External output i/f: --
      RO       : out std_logic;
      AO       : in  std_logic;
      DO       : out std_logic_vector(flit_width_con-1 downto 0)   
);           
end component;

component vc_arbiter
port( 
      -- General Control: --
      RESET     : in  std_logic;  -- Active Low 

      -- VCs Interface: --
      R_ARR     : in  std_logic_vector(num_of_vc_con-1 downto 0); -- requests from different VCs.
      A_ARR     : out std_logic_vector(num_of_vc_con-1 downto 0); -- requests from different VCs.
      DI        : in  data_mvc_bus_type;                          -- array of VC busses.

      -- SPA Interface: --
      RO        : out std_logic;
      AO        : in  std_logic;
      DO        : out std_logic_vector(vc_width+flit_width_con-1 downto 0)
);                
end component;


component spa4
port( 
      RESET   : in  std_logic;
 
      -- MUTEX input i/f: --
      R       : in  std_logic_vector(num_of_sl_con-1 downto 0);
      GATE    : in  std_logic;
      
      -- MUTEX output i/f: --
      G       : out std_logic_vector(num_of_sl_con-1 downto 0);
       
      -- Data Latches: --
      L       : out std_logic_vector(num_of_sl_con-1 downto 0)
);      
end component;

component lanlq1 -- data latch with enable active low and single output.
port(
      EN                             :	in    std_logic;
      D                              :	in    std_logic;
      Q                              :	out   std_logic
);
end component;

component c_element
port( 
      -- Input i/f: --
      A     : in  std_logic;
      B     : in  std_logic;

      -- output i/f: --
      Q     : out std_logic
);           
end component;

component latch_ctrl3 
port( 
      -- General Control: --
      RESET  : in  std_logic;  -- Active  

      -- External input i/f: --
      RI     : in  std_logic;
      AI     : out std_logic;

      -- Latch control i/f: --
      LDO    : out std_logic;
      DI     : in  std_logic;

      -- Internal output i/f: --
      RO     : out std_logic;
      AO     : in  std_logic
); 
end component;

-- NOR (small)
COMPONENT nr02d1 -- drive x1
PORT(
  a1 : IN std_logic; 
  a2 : IN std_logic;
  zn : OUT std_logic
);
END COMPONENT;

component MU4
port(
      I0                             :	in    std_logic;
      I1                             :	in    std_logic;
      I2                             :	in    std_logic;
      I3                             :	in    std_logic;
      Q                              :	out   std_logic;
      S0                             :	in    std_logic;
      S1                             :	in    std_logic
);
end component;

component mutex
port( 

      -- MUTEX input i/f: --
      R1      : in  std_logic;
      R2      : in  std_logic;

      -- MUTEX output i/f: --
      G1      : out std_logic;
      G2      : out std_logic
);           
end component;

component delay_line
generic(
   num_of_buffers : integer := 1
);
port( 
      DI  : in   std_logic;   
      DO  : out  std_logic   
);           
end component;


signal g_sl, ro_spa_c  : std_logic_vector(num_of_sl_con-1 downto 0);

signal ao_reset : std_logic;

signal sig_low  : std_logic;
signal sig_high : std_logic;

signal rl, gate, ldo_latch_out : std_logic;

signal data_out_mux : std_logic_vector(vc_width+msl_ind_width+flit_width_con-1 downto 0);

signal ro_msl_op_int, ro_msl_op_int_not : std_logic;

signal ipidx_arr_sl : ipidx_arr_type; 

type sig_from_ssl_ops_type is array (0 to num_of_sl_con-1) of std_logic_vector(num_of_vc_con-1 downto 0);
signal h_from_ssl_ops, busy_from_ssl_ops, ro_int, ao_int : sig_from_ssl_ops_type;

--type data_mvc_bus_type is array (0 to num_of_vc_con-1) of std_logic_vector(flit_width_con-1 downto 0);
--type data_from_single_vc_type is array (0 to num_of_vc_con-1) of std_logic_vector(flit_width_con-1 downto 0); -- additional bit for VC indication
type data_from_all_vcs_type is array (0 to num_of_sl_con-1) of data_mvc_bus_type;
signal data_from_all_vcs : data_from_all_vcs_type;

-- Iterface signals between VC arbiter and SPA.
signal r_spa, spa_load : std_logic_vector(num_of_sl_con-1 downto 0);

type msl_data_type is array (0 to num_of_sl_con-1) of std_logic_vector(vc_width+flit_width_con-1 downto 0);
signal do_spa, do_spa_del, data_out_spa : msl_data_type; 

signal data_to_ssl : data_to_ssl_op_in_msl_type; -- SL x #ports x #VCs (input)

-- SL x VC(op) x VC(ip) x Ports
type acks_from_vc_op_type is array (0 to num_of_vc_con-1) 
     of signaling_ssl_bus_type;

type all_sl_acks_from_vcop_to_vcip_t is array (0 to num_of_sl_con-1) of acks_from_vc_op_type;
signal all_sl_acks_from_vcop_to_vcip : all_sl_acks_from_vcop_to_vcip_t; 

signal RH_ARR_MTX : signaling_msl_bus_type;          -- pulse valid to OP .

begin

sig_low  <= '0';
sig_high <= '1';

msl_op_sl_gen: for i in 0 to (num_of_sl_con-1) generate -- for each SL
 
 -- 1. Per each SL there is VC admission control: -- 
 u_vcac: vcac
 port map( 
      RESET      => RESET,  -- Active Low 

      H_ARR      => RH_ARR(i), -- SL x VC x ports
      
      RH_ARR_MTX => RH_ARR_MTX(i), -- SL x VC x ports, Header requests from VCAC Mutex

      IPIDX_ARR  => ipidx_arr_sl(i), -- SL x VC (in) x ports
      VC_BUSY    => busy_from_ssl_ops(i),  -- SL x VC (out)
      H_VCS      => h_from_ssl_ops(i)      -- SL x VC (out)      
 );  

 -- Translation from external format "ports x SL x VC" to internal "SL x ports x VC"
 transl_gen: for h in 0 to (num_of_ports_con-1) generate
   data_to_ssl(i)(h) <= DI(h)(i); --all IPs x SL x VC --> data, from all ports x VC (SL x IPs x VC)
 end generate;
 
 -- SVC_SSL_OPS instantiation: VC modules per each SL --
 msl_op_v_gen: for j in 0 to (num_of_vc_con-1) generate

  -- 2. SSL_OP per each SL and per each VC: --
  u_msl_ssl_op_top: msl_ssl_op_top 
  port map( 
      RESET    => RESET,  -- Active  

      H_ARR    => RH_ARR_MTX(i), -- Fixed: Reuven 24.02.07. RH_ARR(i), -- all requests (ip) of this SL
      BT_ARR   => RBT_ARR(i),  -- all requests of this SL
      DATA_I   => data_to_ssl(i), -- data, from all ports x VC
      AI_ARR   => all_sl_acks_from_vcop_to_vcip(i)(j), 

      IPIDX    => ipidx_arr_sl(i)(j),
      H        => h_from_ssl_ops(i)(j),     -- SL x VC (out)
      BUSY     => busy_from_ssl_ops(i)(j),  -- SL x VC (out)

      RO       => ro_int(i)(j),   -- SL x VC (out)
      AO       => ao_int(i)(j),   -- acknoweledge is returned right after grant rises. SL x VC (out)
      DO       => data_from_all_vcs(i)(j) -- SL x VC (out) 
  );     
     
 end generate; -- "j" -- on all VCs inside current SL=i
 
   -- 2.1. OR on Acks fromdifferenc OP-VCs
  msl_op_or11_gen: for yy in 0 to (num_of_vc_con-1) generate -- Ip-VCs
    msl_op_or12_gen: for ww in 0 to (num_of_ports_con-1) generate -- Ip-ports
     AI_ARR(i)(yy)(ww) <= all_sl_acks_from_vcop_to_vcip(i)(0)(yy)(ww) or all_sl_acks_from_vcop_to_vcip(i)(1)(yy)(ww);
   end generate; -- "yy"
  end generate; -- "ww"

 -- 3. VC arbiters (one arbiter per each SL): --
 u_vc_arbiter: vc_arbiter
  port map( 
      RESET     => RESET, 

      R_ARR     => ro_int(i), 
      A_ARR     => ao_int(i), 
      DI        => data_from_all_vcs(i), 

      RO        => r_spa(i),
      AO        => ro_spa_c(i), -- 25.03.07: Reuven: bug fix: old: g_sl(i),   -- grant from SPA
      DO        => do_spa(i)  -- additional bits of VC are added (flits+VC)
  );        
  
  -- 4. Data Latches of the SPA stage
  msl_spa_latch_gen: for k in 0 to (vc_width+flit_width_con-1) generate

   -- Delay line -- timing assumption: hold condition was not satisfied w/o this delay
   --  line. The latches are controlled ony by the Request line (from SPA). 
   -- When the request is de-asserted by VC-Arbiter, the data may change before REQ 
   --  from SPA goes down. Thus, incorrect data will be sampled into the latches.
   -- A better way is to perform here a HS: open latch with REQ+ and close it with ACK+
   --  then a c-element can be used for each register (4 registers per port). This sounds
   --  as a more expensive solution than the buffers of the delay lines, even though it is better.
   u_delay_line_data_latch_spa: delay_line
    generic map(
     num_of_buffers => data_latch_spa_delay_line_length_con
    )
    port map( 
      DI  => do_spa(i)(k),    
      DO  => do_spa_del(i)(k) 
   );          

   u_data_latch_spa: lanlq1
   port map(
      D     => do_spa_del(i)(k), --do_spa(i)(k),
      EN    => spa_load(i), -- not all latches are loaded -- only those that have request.
      Q     => data_out_spa(i)(k)
   );
   
  end generate; -- "k"
 
  -- 5. C-elements -- for saving arbitration result (grant).
  u_c_element_grant: c_element
  port map( 
      A     => g_sl(i),  -- SL
      B     => ro_msl_op_int_not, -- single bit from Latch Controller

      Q     => ro_spa_c(i) -- SL
  ); 

end generate; -- "i" (on all SLs)

-- 6. SPA
u_spa4: spa4
port map( 
      RESET  => RESET,

      R      => r_spa, -- from VC arbiter.

      GATE   => gate,  -- from Latch controller

      G      => g_sl,  
      
      L      => spa_load
);   

-- 7. RL OR: request to output buffer latch controller, OR on all SLs: --
rl <= ro_spa_c(0) or ro_spa_c(1) or ro_spa_c(2) or ro_spa_c(3);

-- 8. SL Mux: --
sl_out_mux_proc: process(ro_spa_c, data_out_spa)
begin
 case ro_spa_c is  -- construction of final word type: VC+SL+DATA
  when "0001" =>   -- format:  VC-bits  -----------   SL  -- data + flit type
   data_out_mux <= data_out_spa(0)(flit_width_con) & "00" & data_out_spa(0)(flit_width_con-1 downto 0);
  when "0010" =>
   data_out_mux <= data_out_spa(1)(flit_width_con) & "01" & data_out_spa(1)(flit_width_con-1 downto 0);
  when "0100" =>
   data_out_mux <= data_out_spa(2)(flit_width_con) & "10" & data_out_spa(2)(flit_width_con-1 downto 0);
  when "1000" =>
   data_out_mux <= data_out_spa(3)(flit_width_con) & "11" & data_out_spa(3)(flit_width_con-1 downto 0);
  when others =>
   data_out_mux <= data_out_spa(0)(flit_width_con) & "00" & data_out_spa(0)(flit_width_con-1 downto 0);
 end case;
end process;

-- 9. Output Latch controller: --
u_latch_ctrl3: latch_ctrl3 
port map( 
      RESET  => RESET,    

      RI     => rl,
      AI     => gate,

      LDO    => ldo_latch_out,
      DI     => sig_low,

      RO     => ro_msl_op_int,
      AO     => AO
); 

RO <= ro_msl_op_int;

-- 10. Reversing the RO + Reset: --
u_ao_not: nr02d1
port map(
      a1 => RESET,
      a2 => ro_msl_op_int,
      zn => ro_msl_op_int_not
);


-- 11. Output Latch: --
msl_op_latch_gen: for k in 0 to (vc_width+msl_ind_width+flit_width_con-1) generate

 u_data_latch_out: lanlq1
 port map(
      D     => data_out_mux(k),
      EN    => ldo_latch_out,
      Q     => DO(k)
 );
  
end generate;

-------------------------------------------------------------------------------
end msl_op_arch;
-------------------------------------------------------------------------------                 

   
-------------------------------------------------------------------------------
configuration  msl_op_cfg  of msl_op is
-------------------------------------------------------------------------------
   for msl_op_arch
   end for;
-------------------------------------------------------------------------------
end  msl_op_cfg;              
-------------------------------------------------------------------------------
                 
